package com.Lyf.manager.util;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Random;

public class AESUtil {
    //AES要求key长度不低于16位
    //加密密钥
    private static final String KEY="0123456789abcdef";

    //加密方式
    private static final String ENCRYPTION_MODE="AES";
    //加密模式:ECB
    private static final String AES_ECB="AES/ECB/PKCS5Padding";
    //加密模式:CBC
    private static final String AES_CBC="AES/CBC/PKCS5Padding";
    //加密模式:CFB
    private static final String AES_CFB="AES/CFB/PKCS5Padding";
    //AES中的IV必须是16字节(128位)长  Wrong IV length: must be 16 bytes long
    private static final Integer IV_LENGTH=16;

    //编码
    public static final Base64.Encoder Base64Encoder = Base64.getEncoder();

    //解码
    public static final Base64.Decoder Base64Decoder = Base64.getDecoder();

    //判空操作
    public static boolean isEmpty(String str) {
        return str == null || str.length() == 0 || "".equals(str.trim());
    }

    //初始化向量(IV),一个随机生成的字节数组，用于增加加密和解密的安全性
    public static String getIV()
    {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer stringBuffer = new StringBuffer();
        for(int i=0;i<IV_LENGTH;i++)
        {
            int index = random.nextInt(str.length());
            stringBuffer.append(str.charAt(index));
        }
        return stringBuffer.toString();
    }

    //获取一个AES密钥规范
    private static SecretKeySpec getSecretKeySpec(String key)
    {
        return new SecretKeySpec(key.getBytes(), ENCRYPTION_MODE);
    }


    //ECB加密模式
    public static String encrypt(String text,String key)
    {
        if(isEmpty(key) || isEmpty(text))
        {
            return null;
        }

        try {
            //创建AES加密器
            Cipher cipher = Cipher.getInstance(AES_ECB);
            SecretKeySpec secretKeySpec = getSecretKeySpec(key);
            cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec);


            //加密
            byte[] encryptedBytes = cipher.doFinal(text.getBytes());

            //此处使用BASE64做转码功能,同时起到2次加密作用
            return Base64Encoder.encodeToString(encryptedBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    //ECB模式解密
    public static String decrypt(String text,String key)
    {
        if(isEmpty(key) || isEmpty(text))
        {
            return null;
        }
        try{
            // 创建AES加密器
            Cipher cipher = Cipher.getInstance(AES_ECB);
            SecretKeySpec secretKeySpec = getSecretKeySpec(key);
            cipher.init(Cipher.DECRYPT_MODE,secretKeySpec);

            //先用BASE64解密
            byte[] decode = Base64Decoder.decode(text);
            //ECB解密
            byte[] bytes = cipher.doFinal(decode);
            //恢复明文之前的样子
            return new String(bytes, StandardCharsets.UTF_8);

        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

    //自定义加密模式
    /**
     * @param text 需要加密的内容
     * @param key  加密密钥
     * @param iv   初始向量值
     * @param mode 加密模式
     */
    public static String encrypt(String text,String key,String iv,String mode)
    {
        if(isEmpty(key) || isEmpty(text) || isEmpty(iv))
        {
            return null;
        }
        try{
            Cipher cipher = Cipher.getInstance(mode);
            SecretKeySpec secretKeySpec = getSecretKeySpec(key);
            cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,new IvParameterSpec(iv.getBytes()));

            //开始加密
            byte[] encryptedBytes = cipher.doFinal(text.getBytes());
            //Base64编码双重加密
            return Base64Encoder.encodeToString(encryptedBytes);
        }catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }

    //自定义解密方式
    public static String decrypt(String text,String key,String iv,String mode)
    {
        if(isEmpty(key) || isEmpty(text) || isEmpty(iv))
        {
            return null;
        }
        try {
            Cipher cipher = Cipher.getInstance(mode);
            SecretKeySpec secretKeySpec = getSecretKeySpec(key);
            cipher.init(Cipher.DECRYPT_MODE,secretKeySpec,new IvParameterSpec(iv.getBytes()));

            //解密
            //Base64先进行解密操作
            byte[] decode = Base64Decoder.decode(text);
            byte[] bytes = cipher.doFinal(decode);
            return new String(bytes, StandardCharsets.UTF_8);

        }catch (Exception e)
        {
            throw new RuntimeException(e);
        }

    }
    public static void main(String[] args) {
        String str="123456";
        System.out.println("原始字符串为:"+str);

        //AES_ECB模式加密(已使用Base64二次加密)
        String encrypt = encrypt(str, KEY);
        System.out.println("AES_ECB模式加密:"+encrypt);
        //AES_ECB模式解密
        System.out.println("AES_ECB模式解密:"+decrypt(encrypt,KEY));


        //CBC和CFB模式需要使用到vi
        String iv=getIV();
        System.out.println("iv:"+ iv);


        String encryptTextCBC = encrypt(str, KEY, iv, AES_CBC);
        System.out.println("CBC 加密后内容：" + encryptTextCBC);
        System.out.println("CBC 解密后内容：" + decrypt(encryptTextCBC, KEY, iv, AES_CBC));


        String encryptTextCFB = encrypt(str, KEY, iv, AES_CFB);
        System.out.println("CFB 加密后内容：" + encryptTextCFB);
        System.out.println("CFB 解密后内容：" + decrypt(encryptTextCFB, KEY, iv, AES_CFB));
    }

}
